package com.lin.codesnippet.treeNome.avltree;

//AVL树的节点类
class AVLNode<T> {
    T element;
    AVLNode<T> left;
    AVLNode<T> right;
    int height;//记录高度

    //构造器
    public AVLNode(T theElement) {
        this(theElement, null, null);
        element = theElement;
    }

    public AVLNode(T theElement, AVLNode<T> left, AVLNode<T> right) {
        this.element = theElement;
        this.left = left;
        this.right = right;
        this.height = 0;
    }
}

//AVL树
public class AVLTree2<T extends Comparable> {
    //私有属性
    private AVLNode<T> root;//根节点

    private int height(AVLNode<T> t) {
        return t == null ? -1 : t.height;
    }

    //构造方法
    AVLTree2() {
        this.root = null;
    }

    //插入操作
    public void insert(T x) {
        this.root = insert(x, root);
    }

    //删除操作
    public void remove(T x) {
        this.root = remove(x, root);
    }

    //中序打印操作
    public void infPrintTree() {
        infPrintTree(root);
        System.out.println();
    }

    //判断是否是AVL树
    public boolean isAVL() {
        return Math.abs(maxDeep(root.right) - maxDeep(root.left)) < 2;
    }

    public AVLNode<T> findMax(AVLNode<T> t) {
        if (t == null)
            throw new RuntimeException("this AVLNode is Empty");
        if (t.right == null)
            return t;
        return findMax(t.right);
    }

    public AVLNode<T> insert(T x, AVLNode<T> t) {
        if (t == null)//传入节点为空，则将该节点作为根节点返回
            return new AVLNode<>(x, null, null);
        int compareResult = x.compareTo(t.element);
        if (compareResult < 0)//传入元素x小于t
            t.left = insert(x, t.left);
        else if (compareResult > 0)//传入元素x大于t
            t.right = insert(x, t.right);
        return balance(t);
    }

    //重新进行平衡
    public AVLNode<T> balance(AVLNode<T> t) {
        if (t == null)
            return t;
        if (height(t.left) - height(t.right) > 1) {//左插入
            if (height(t.left.left) >= height(t.left.right)) //左左插入  情形1
                t = singleRightRotate(t);//右旋
            else //左右插入           情形2
                t = doubleLeftRightRotate(t);//左右双旋
        }
        if (height(t.right) - height(t.left) > 1) {//右插入
            if (height(t.right.right) >= height(t.right.left)) //右右插入    情形3
                t = singleLeftRotate(t);//左旋
            else //右左插入       情形4
                t = doubleRightLeftRotate(t);//右左双旋
        }
        t.height = height(t.right) > height(t.left) ? height(t.right) + 1 : height(t.left) + 1;
        return t;
    }

    //右单旋
    private AVLNode<T> singleRightRotate(AVLNode<T> t) {
        System.out.println("进行右旋转==============>>>");
        AVLNode<T> r = t.left;
        t.left = r.right;
        r.right = t;
        t.height = height(t.left) > height(t.right) ? height(t.left) + 1 : height(t.right) + 1;
        r.height = height(t.right) > height(r) ? height(t.right) + 1 : height(r) + 1;
        return r;
    }

    //左单旋
    private AVLNode<T> singleLeftRotate(AVLNode<T> t) {
        System.out.println("进行左旋转==============>>>");
        AVLNode<T> r = t.right;
        t.right = r.left;
        r.left = t;
        t.height = height(t.left) > height(t.right) ? height(t.left) + 1 : height(t.right) + 1;
        r.height = height(t.left) > height(r) ? height(t.left) + 1 : height(r) + 1;
        return r;
    }

    //右左双旋
    private AVLNode<T> doubleRightLeftRotate(AVLNode<T> t) {
        System.out.println("进行右左双旋==============>>>");
        t.right = singleRightRotate(t.right);
        return singleLeftRotate(t);
    }

    //左右双旋
    private AVLNode<T> doubleLeftRightRotate(AVLNode<T> t) {
        System.out.println("进行左右双旋==============>>>");
        t.left = singleLeftRotate(t.left);
        return singleRightRotate(t);
    }

    public AVLNode<T> remove(T x, AVLNode<T> t) {
        if (t == null)//传入节点为空
            return t;
        int compareResult = x.compareTo(t.element);
        if (compareResult < 0)
            t.left = remove(x, t.left);
        else if (compareResult > 0)
            t.right = remove(x, t.right);
        else if (t.left != null && t.right != null) { //有两个儿子
            t.element = findMax(t.left).element;
            remove(t.element, t.left);
        } else //单儿子情形
            t = t.left == null ? t.right : t.left;
        if (t != null)
            t.height = height(t.right) > height(t.left) ? height(t.right) + 1 : height(t.left) + 1;
        return balance(t);
    }

    public int maxDeep(AVLNode<T> t) {
        int dl, dr;//记录左右树的深度
        if (t == null)
            return 0;
        else {
            dl = maxDeep(t.left);
            dr = maxDeep(t.right);
        }
        return dl > dr ? dl + 1 : dr + 1;
    }


    public void infPrintTree(AVLNode<T> t) {
        if (t == null)
            return;
        infPrintTree(t.left);
        System.out.print(t.element + " ");
        infPrintTree(t.right);
    }

//    public static void main(String[] args) {
//        AVLTree2 avlT = createAVLTree();
//        System.out.println("是否是AVL树:" + avlT.isAVL());
//        System.out.println("中序打印出该树===>>>");
//        avlT.infPrintTree();
//        avlT.remove(60);
//        avlT.insert(35);
//    }

    /**
     * 50
     * /    \
     * 30      60
     * /   \
     * 20     40
     *
     * @return
     */
    private static AVLTree2 createAVLTree() {
        AVLTree2<Integer> avlT = new AVLTree2();
        avlT.insert(50);
        avlT.insert(60);
        avlT.insert(30);
        avlT.insert(40);
        avlT.insert(20);
        return avlT;
    }
}